package com.jzr.netty.common.service;

import com.jzr.netty.common.base.BaseMsg;
import com.jzr.netty.common.base.ConnectionException;
import com.jzr.netty.common.base.SendException;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * @author 陈旭东
 * @version 1.0
 * @date 2018年11月10日
 */
public class AdminNettyClient implements AutoCloseable {
    private AdminClientHandler clientHandler;
    private EventLoopGroup group;
    private SocketChannel channel;
    private Logger log = LoggerFactory.getLogger(this.getClass());

    public AdminNettyClient(String host, int port) throws ConnectionException {
        // 配置客户端NIO线程组
        try {
            group = new NioEventLoopGroup();
            clientHandler = new AdminClientHandler();
            try {
                Bootstrap b = new Bootstrap();
                b.group(group).channel(NioSocketChannel.class)
                        .option(ChannelOption.TCP_NODELAY, true)
                        .handler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            public void initChannel(SocketChannel ch)
                                    throws Exception {
                                ch.pipeline().addLast(
                                        new ObjectEncoder(),
                                        new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
                                        clientHandler);
                            }
                        });

                // 发起异步连接操作
                ChannelFuture f = b.connect(host, port);
                f.awaitUninterruptibly();
                assert f.isDone();
                if (f.isSuccess()) {
                    channel = (SocketChannel) f.channel();
                    log.info("Connect Server Success!");
                } else {
                    throw new ConnectionException("链接netty服务失败," + f.cause().getMessage());
                }
            } finally {
            }
        }catch (Throwable e){
            throw new ConnectionException("链接netty服务失败,"+e.getMessage());
        }
    }

    public void close() {
        if (channel != null) {
            channel.closeFuture();
        }
        // 优雅退出，释放NIO线程组
        if (group != null) {
            group.shutdownGracefully();
        }
    }
    public BaseMsg send(BaseMsg request) throws SendException {
        try {
            CountDownLatch latch = new CountDownLatch(1);
            clientHandler.reset(latch);
            ChannelFuture f = channel.writeAndFlush(request);
            f.awaitUninterruptibly();
            assert f.isDone();
            if (f.isSuccess()) {
                latch.await(30, TimeUnit.SECONDS);
                BaseMsg response = clientHandler.getResponse();
                return response;
            } else {
                throw new SendException("发送数据到netty失败,"+f.cause().getMessage());
            }
        }catch (Throwable e){
            throw new SendException("发送数据到netty失败,"+e.getMessage());
        }
    }
}